package com.hatricks.is.capturecode;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.hatricks.is.exceptionstrace.BizException;
import lombok.SneakyThrows;

import java.util.concurrent.Semaphore;

/**
 * @packageName: com.hatricks.is.capturecode
 * @className: CaptureMessage
 * @author: yanyuhui y568821795@outlook.com
 * @date: 2024-12-03 14:36
 * @description: 验证码消息
 */
public abstract class CaptureMessage {

    public static final String PHONE_NUMBERS_LIMIT_CHECK = "PHONE_NUMBERS_LIMIT_CHECK:";
    public static final Semaphore semaphore = new Semaphore(1);

    public String generateCaptureCode() {
        return RandomUtil.randomNumbers(6);
    }

    /**
     * 同一时间节点 同一方法只能发送一条消息
     *
     * @param phoneNumber   电话
     * @param templateEnums 模板
     */
    @SneakyThrows
    public String sendMessage(String phoneNumber, TemplateEnums templateEnums) {
        semaphore.acquire();
        String captureCode;
        try {
            String key = PHONE_NUMBERS_LIMIT_CHECK + phoneNumber;
            checkPhoneNumber(key);
            captureCode = generateCaptureCode();
            MessageSend.sendMessage(captureCode, phoneNumber, templateEnums);
            saveCaptureCode(captureCode, phoneNumber, templateEnums);
            saveCheckLimits(key);
        } finally {
            semaphore.release();
        }
        return captureCode;
    }

    public void checkCaptureCode(String captureCode, String phoneNumber, TemplateEnums templateEnums) {
        String memoryCaptureCode = getCaptureCode(phoneNumber, templateEnums);
        if (StrUtil.isEmpty(memoryCaptureCode)) {
            throw new BizException("验证码已过期,请重新获取");
        }
        if (!StrUtil.equals(captureCode, memoryCaptureCode)) {
            throw new BizException("验证码输入有误,请重新输入");
        }
    }


    /**
     * 1分钟内只能发送一次验证码
     *
     * @param key 验证码
     */
    private void checkPhoneNumber(String key) {
        Integer numbers = getCheckLimits(key);
        if (numbers != null) {
            throw new BizException("1分钟内只能获取一次验证码");
        }
    }

    protected abstract Integer getCheckLimits(String key);

    protected abstract void saveCheckLimits(String key);

    protected abstract void saveCaptureCode(String captureCode, String phoneNumber, TemplateEnums templateEnums);

    protected abstract String getCaptureCode(String phoneNumber, TemplateEnums templateEnums);
}
